package com.azh.server.datam.page;

import java.util.Arrays;

import com.azh.server.datam.pagecache.PageCache;
import com.azh.server.util.Parser;

/**
 * @author zhaozhenhang <zhaozhenhang@kuaishou.com>
 * Created on 2022-04-25
 * 普通页 以一个2字节无符号数开始，这个无符号数代表这页空闲位置的offset，剩下的部分就是实际存储的数据
 */
public class PageNormal {

    private static final short of_free = 0;
    private static final short of_data = 2;
    public static final int max_free_space = PageCache.PAGE_SIZE - of_data;

    public static byte[] initRaw() {
        byte[] raw = new byte[PageCache.PAGE_SIZE];
        setFSO(raw, of_data);
        return raw;
    }

    /**
     * 将raw数据插入page中, 返回插入的位置
     * @param page
     * @param raw
     * @return
     */
    public static short insert(Page page, byte[] raw) {
        page.setDirty(true);
        short offset = getFSO(page.getData());
        System.arraycopy(raw, 0, page.getData(), offset, raw.length);
        setFSO(page.getData(), (short) (offset + raw.length));
        return offset;
    }

    /**
     * 返回页面空闲空间大小
     * @param page
     * @return
     */
    public static int getFreeSpace(Page page) {
        return PageCache.PAGE_SIZE - (int) getFSO(page.getData());
    }

    public static short getFSO(Page page) {
        return getFSO(page.getData());
    }

    /**
     * 将raw 插入到page中offset的位置，并将page的offset设置为较大的offset
     * 该方法用于数据库崩溃时恢复数据用
     * @param page
     * @param raw
     * @param offset
     */
    public static void recoverInsert(Page page, byte[] raw, short offset) {
        page.setDirty(true);
        System.arraycopy(raw, 0, page.getData(), offset, raw.length);
        short rawFSO = getFSO(page.getData());
        if (rawFSO < offset + raw.length) {
            setFSO(page.getData(), (short) (offset + raw.length));
        }
    }

    /**
     * 将raw插入page的offset位置，不更新对应的offset
     * @param page
     * @param raw
     * @param offset
     */
    public static void recoverUpdate(Page page, byte[] raw, short offset) {
        page.setDirty(true);
        System.arraycopy(raw, 0, page.getData(), offset, raw.length);
    }

    /**
     * 更新free space offset （FSO）
     * @param raw
     * @param ofData
     */
    private static void setFSO(byte[] raw, short ofData) {
        System.arraycopy(Parser.shortToByte(ofData), 0, raw, of_free, ofData);
    }

    /**
     * 获取该page的free space offset
     * @param raw
     * @return
     */
    private static short getFSO(byte[] raw) {
        return Parser.parseShort(Arrays.copyOfRange(raw, 0, 2));
    }
}
